<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
import html2canvas from 'html2canvas';
import Moveable from 'moveable';
import { useStore } from '../../store';

const initWidth = 200;
const initHeight = 600;
const initPropWidth = 100;
const initPropHeight = 100;
const store = useStore();
const canvasContainerWarp = ref<any>(null);
const canvasContainer = ref<any>(null);
const mainImage = ref<any>(null);
const propImage = ref<any>(null);
let mainMoveable: any = null;
let propMoveable: any = null;

const onCanvasClick = () => {
  console.log('🚀 ~ onCanvasClick ~ onCanvasClick:');
  mainMoveable && (mainMoveable.target = null);
  propMoveable && (propMoveable.target = null);
};

// 监听画布尺寸宽高 | 容器宽高
const canvasWrap = ref<any>({
  scale: 1
});
const viewData = reactive({
  background: {
    type: 'background',
    src: ''
  },
  digital: {
    type: 'digital',
    width: initWidth,
    height: initHeight,
    left: 0,
    top: 0,
    src: '',
    init: false
  },
  material: {
    type: 'material',
    width: initPropWidth,
    height: initPropHeight,
    left: 0,
    top: 0,
    src: '',
    angle: 0,
    init: false
  }
});
watch(
  () => store.canvasConfig.size,
  (newValue, oldValue) => {
    if (newValue) {
      console.log('======= ~ watch ~ store.isGetDraftData:', store.isGetDraftData);
      if (!canvasContainerWarp.value) return;
      if (store.isGetDraftData) return;
      updateCanvasSize();
      // 清空画布&清理已选
      console.log(newValue, oldValue, 'newValue, oldValue');
      if (newValue !== oldValue) {
        viewData.material.width = initPropWidth;
        viewData.material.height = initPropHeight;
        viewData.material.left = 0;
        viewData.material.top = 0;

        viewData.digital.width = initWidth;
        viewData.digital.height = initHeight;
        viewData.digital.left = 0;
        viewData.digital.top = 0;
        resetMoveableInfo();
      }
    }
  },
  { immediate: true, deep: true }
);

async function resetMoveableInfo() {
  mainImage.value.style.width = `${initWidth}px`;
  await computedImageSize({
    instance: viewData.digital,
    imgUrl: viewData.digital.src,
    nowWidth: viewData.digital.width,
    moveableEle: mainMoveable,
    element: mainImage.value
  });
  mainImage.value.style.transform = '';
  if (propImage.value) {
    console.log(propImage.value, 'propImage.value');
    propImage.value.style.width = `${initPropWidth}px`;
    await computedImageSize({
      instance: viewData.material,
      imgUrl: viewData.material.src,
      nowWidth: viewData.material.width,
      moveableEle: propMoveable,
      element: propImage.value
    });
    propImage.value.style.transform = '';
  }
}

// 计算缩放比例
function calculateTransform(container: any, aspectRatio: any) {
  const containerWidth = container.offsetWidth - 20;
  const containerHeight = container.offsetHeight;
  const sourceWidth = aspectRatio.resolution.width;
  const sourceHeight = aspectRatio.resolution.height;

  // 计算最大可用高度（减去header和预留空间）
  const maxAvailableHeight = window.innerHeight - 64 - 100;
  const minHeight = 532;

  // 计算基于宽度的缩放比例
  const scaleByWidth = containerWidth / sourceWidth;

  // 计算基于高度的缩放比例
  let scaleByHeight;
  if (aspectRatio.direction === 'vertical') {
    // 竖屏模式：需要考虑最小高度和最大高度限制
    const targetHeight = Math.min(
      Math.max(minHeight, containerWidth * (sourceHeight / sourceWidth)),
      maxAvailableHeight
    );
    scaleByHeight = targetHeight / sourceHeight;
  } else {
    // 横屏模式：直接使用容器高度计算
    scaleByHeight = containerHeight / sourceHeight;
  }

  // 返回较小的缩放比例，确保内容完全适配容器
  return Math.min(scaleByWidth, scaleByHeight);
}

// url更新
watch(
  () => [store.digital.url, store.bg.url, store.material.url],
  () => {
    console.log('--------------------------------------------------------');
    syncStoreDataToCanvas();
  },
  { deep: true }
);

// 配置回显
function getCacheConfig(flag: string) {
  const config = store.canvas.find((item: any) => item.type === flag);
  return config || {};
}

// 导出画布内容 => 3s防抖
// const canvasExport = useDebounceFn(canvasExportFn, 3000);
const sleep = (time: number) => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(true);
    }, time);
  });
};

async function computedImageSize({
  instance,
  imgUrl,
  nowWidth,
  moveableEle,
  element
}: {
  instance: any;
  imgUrl: any;
  nowWidth: number;
  moveableEle: any;
  element: any;
}) {
  const { width, height } = await getImageDimensions(imgUrl);
  const scale = width / height;

  let newHeight: number = nowWidth / scale;

  let newWidth: number = nowWidth;

  /** 顶部的位置+计算后的高度 是否大于画布高度 */
  if (instance.top + newHeight - canvasContainer.value.clientHeight > 0) {
    newHeight = canvasContainer.value.clientHeight - instance.top;
    newWidth = newHeight * scale;
  }

  element.style.height = `${newHeight}px`;

  element.style.width = `${newWidth}px`;

  instance.height = newHeight;
  instance.width = newWidth;
  console.log(element.style.height, element.style.width, 'computedImageSize');

  console.log('new instance: ', instance);
  setTimeout(() => {
    moveableEle.updateRect();
  }, 150);
}

function setBackgroundData() {
  if (store.bg && store.bg.url) {
    // addBackground(store.bg.url, getCacheConfig('background')); // 背景
    const oldConfig = getCacheConfig('background');
    const oldUrl = oldConfig.url;
    viewData.background.src = store.bg.url || oldUrl;
  }
}

async function setDigitalData() {
  const isInit = store.digital && store.digital.url && !viewData.digital.src;
  if (isInit) {
    const oldConfig = getCacheConfig('digital');
    const oldUrl = oldConfig.url;
    viewData.digital.src = store.digital.url || oldUrl;
    if (!viewData.digital.init) {
      viewData.digital.width = oldConfig.width || initWidth;
      viewData.digital.height = oldConfig.height || initHeight;
      viewData.digital.left = oldConfig.left || 0;
      viewData.digital.top = oldConfig.top || 0;
    }
    await computedImageSize({
      instance: viewData.digital,
      imgUrl: viewData.digital.src,
      nowWidth: viewData.digital.width,
      moveableEle: mainMoveable,
      element: mainImage.value
    });
    if (!viewData.digital.init) {
      mainImage.value.style.transform = `translate(${viewData.digital.left}px, ${viewData.digital.top}px)`;
    }
    console.log(viewData.digital.width, viewData.digital.height, '更新的 offsetWidth 和 offsetHeight ');
    viewData.digital.init = true;
    return;
  }
  // 更新操作
  const isUpdate = store.digital && store.digital.url && store.digital.url !== viewData.digital.src;
  if (!isUpdate) return;
  viewData.digital.src = store.digital.url;
  await computedImageSize({
    instance: viewData.digital,
    imgUrl: viewData.digital.src,
    nowWidth: viewData.digital.width,
    moveableEle: mainMoveable,
    element: mainImage.value
  });
}

// eslint-disable-next-line complexity
async function syncStoreDataToCanvas() {
  setBackgroundData();
  await setDigitalData();
  const isInit = store.material && store.material.url && !viewData.material.src;
  if (isInit) {
    const oldConfig = getCacheConfig('material');
    const oldUrl = oldConfig.url;
    viewData.material.src = store.material.url || oldUrl;
    if (!viewData.material.init) {
      viewData.material.width = oldConfig.width || initPropWidth;
      viewData.material.height = oldConfig.height || initPropHeight;
      viewData.material.left = oldConfig.left || 0;
      viewData.material.top = oldConfig.top || 0;
    }
    if (!propMoveable) {
      await sleep(1);
      await initPropContent();
      updateBounds();
    }
    await computedImageSize({
      instance: viewData.material,
      imgUrl: viewData.material.src,
      nowWidth: viewData.material.width,
      moveableEle: propMoveable,
      element: propImage.value
    });
    if (!viewData.material.init) {
      propImage.value.style.transform = `translate(${viewData.material.left}px, ${viewData.material.top}px)`;
    }
    console.log(viewData.material.width, viewData.material.height, 'syncStoreDataToCanvas');
    viewData.material.init = true;
  }
  const isUpdate = store.material && store.material.url && store.material.url !== viewData.material.src;
  if (isUpdate) {
    viewData.material.src = store.material.url;
    await computedImageSize({
      instance: viewData.material,
      imgUrl: viewData.material.src,
      nowWidth: viewData.material.width,
      moveableEle: propMoveable,
      element: propImage.value
    });
  }
  const isDestroy = !(store.material && store.material.url);
  if (isDestroy) {
    viewData.material.src = '';
    propMoveable && propMoveable.destroy();
    propMoveable = null;
  }
}

const warpperStyle = computed(() => {
  const currentConfig = store.dict.canvas.find((item: any) => item.size === store.canvasConfig.size);
  return {
    width: `${currentConfig.resolution.width}px`,
    height: `${currentConfig.resolution.height}px`,
    transform: `scale(${canvasWrap.value.scale}) translate(-50%, -50%)`,
    transformOrigin: store.canvasConfig.direction === 'horizontal' ? 'left top' : 'top left'
  };
});

watch(
  () => warpperStyle.value,
  () => {
    const currentConfig = store.dict.canvas.find((item: any) => item.size === store.canvasConfig.size);
    updateBounds(currentConfig.resolution.width, currentConfig.resolution.height);
    updateCanvasSize();
  }
);

const createMoveable = async (element: any, config: any, handlers: any) => {
  element.style.width = `${config.initWidth}px`;
  console.log(canvasContainer.value.clientWidth, canvasContainer.value.clientHeight, 'canvasContainer===.value');
  await nextTick();
  const moveable = new Moveable(canvasContainer.value, {
    target: element,
    draggable: true,
    scalable: true,
    resizable: true,
    keepRatio: true,
    pinchable: true,
    origin: false,
    throttleDrag: 0,
    throttleResize: 0,
    zoom: 1,
    edge: true,
    snappable: true
  })
    .on('drag', handlers.onDrag)
    .on('resize', handlers.onResize);

  // 添加事件监听
  ['dragstart', 'click'].forEach(eventName => {
    element.addEventListener(eventName, (e: Event) => {
      e.preventDefault();
      e.stopPropagation();
      moveable.target = element;
    });
  });

  return moveable;
};

const initMainContent = async () => {
  mainMoveable = await createMoveable(
    mainImage.value,
    { initWidth },
    {
      onDrag: ({ target, transform, translate }: any) => {
        target.style.transform = transform;
        viewData.digital.left = translate[0];
        viewData.digital.top = translate[1];
        console.log(
          viewData.digital.left,
          viewData.digital.width,
          viewData.digital.left + viewData.digital.width,
          'viewData.digital.left=====>',
          viewData.digital
        );
      },

      onResize: ({ target, width, height, drag }: any) => {
        // 限制最小尺寸但不直接返回
        const finalWidth = Math.max(width, 100);
        const finalHeight = Math.max(height, 100);

        console.log(finalWidth, finalHeight, 'onResize');
        target.style.width = `${finalWidth}px`;
        target.style.height = `${finalHeight}px`;
        target.style.transform = drag.transform;
        viewData.digital.width = finalWidth;
        viewData.digital.height = finalHeight;
      }
    }
  );
  updateBounds();
};

const initPropContent = async () => {
  propMoveable = await createMoveable(
    propImage.value,
    { initWidth: initPropWidth },
    {
      onDrag: ({ target, transform, translate }: any) => {
        target.style.transform = transform;
        viewData.material.left = translate[0];
        viewData.material.top = translate[1];
      },
      onResize: ({ target, width, height, drag }: any) => {
        // 限制最小尺寸但不直接返回
        const finalWidth = Math.max(width, 80);
        const finalHeight = Math.max(height, 80);

        target.style.width = `${finalWidth}px`;
        target.style.height = `${finalHeight}px`;
        target.style.transform = drag.transform;
        viewData.material.width = finalWidth;
        viewData.material.height = finalHeight;
      }
    }
  );
};

function canvasExportFn() {
  const custom: any[] = [];
  Object.keys(viewData).forEach((key: any) => {
    const item = (viewData as any)[key];
    custom.push(item);
  });
  store.updateCanvasObjects(custom); // 存储画布导出对象内容
}
async function canvasExportCover(save = true) {
  const content = canvasContainer.value;
  // 设置最大尺寸限制
  const maxWidth = 1920; // 最大宽度
  const maxHeight = 1920; // 最大高度

  // 计算实际输出尺寸
  const scale = save ? 2 : 2;
  const contentWidth = content.offsetWidth * scale;
  const contentHeight = content.offsetHeight * scale;

  // 如果超出最大尺寸，计算新的缩放比例
  let finalScale = scale;
  if (contentWidth > maxWidth || contentHeight > maxHeight) {
    const widthRatio = maxWidth / content.offsetWidth;
    const heightRatio = maxHeight / content.offsetHeight;
    finalScale = Math.min(widthRatio, heightRatio);
  }

  const canvas = await html2canvas(content, {
    scale: finalScale,
    useCORS: true,
    allowTaint: false,
    backgroundColor: null,
    logging: false,
    imageTimeout: 0,
    onclone: cb => {
      const moveableControlBox = cb.getElementsByClassName('moveable-control-box');
      Array.from(moveableControlBox).forEach((item: any) => {
        item.style.display = 'none';
      });
    }
  });
  const dataURL = canvas.toDataURL('image/png', 0.8);
  return store.updateCanvasCover(dataURL, save);
}

function getImageDimensions(url: string): Promise<{ width: number; height: number }> {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      console.log('img.onload', img.width, img.height);
      resolve({ width: img.width, height: img.height });
    };
    img.onerror = () => {
      reject(new Error(`Could not load image at ${url}`));
    };
    img.src = url;
  });
}

let resizeObserver: any = null;

onMounted(() => {
  updateCanvasSize();
  if (canvasContainerWarp.value) {
    resizeObserver = new ResizeObserver(entries => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        console.log(`Container size changed: width ${width} px, height ${height} px`);
        updateCanvasSize();
      }
    });
    resizeObserver.observe(canvasContainerWarp.value);
  }
  setTimeout(() => {
    initMainContent();
    updateBounds();
  }, 1);
});

function updateBounds(width?: number, height?: number) {
  if (!canvasContainer.value) {
    console.log('canvasContainer.value block updateBounds', width);
    return;
  }
  if (propMoveable) {
    propMoveable.bounds = {
      left: 0,
      top: 0,
      right: width || canvasContainer.value.clientWidth,
      bottom: height || canvasContainer.value.clientHeight
    };
    propMoveable.updateRect();
  }
  if (mainMoveable) {
    mainMoveable.bounds = {
      left: 0,
      top: 0,
      right: width || canvasContainer.value.clientWidth,
      bottom: height || canvasContainer.value.clientHeight
    };
    mainMoveable.updateRect();
  }
  console.log(
    canvasContainer.value.clientWidth,
    canvasContainer.value.clientHeight,
    'updateBound=======',
    mainMoveable,
    propMoveable
  );
}

function updateCanvasSize() {
  const currentConfig = store.dict.canvas.find((item: any) => item.size === store.canvasConfig.size);

  const scale = calculateTransform(canvasContainerWarp.value, currentConfig);
  canvasWrap.value.scale = scale;
  console.log(scale, 'scale=====>');
}
onUnmounted(() => {
  if (resizeObserver) {
    resizeObserver.disconnect();
  }
});
defineExpose({ canvasExportCover, canvasExportFn });
const imageLoad = ref(false);
watch(
  () => viewData.background.src,
  () => {
    console.warn(viewData.background.src, 'viewData.background.src');

    getImageDimensions(viewData.background.src).then(() => {
      imageLoad.value = true;
    });
  }
);
</script>

<template>
  <div class="h-full w-full overflow-hidden">
    <!-- loading -->
    <div
      v-show="!imageLoad"
      class="absolute-tl z-10 wh-full flex-center"
      style="background-color: #0f101a; padding-top: -5rem"
    >
      <div class="flex-center">
        <NSpin />
      </div>
    </div>
    <div
      ref="canvasContainerWarp"
      :style="{ opacity: imageLoad ? 1 : 0 }"
      class="canvasContainerWarp relative flex items-center justify-center"
    >
      <div ref="canvasContainer" :style="warpperStyle" class="canvasContainer absolute wh-full" @click="onCanvasClick">
        <!-- A: 背景图 -->
        <img :src="viewData.background.src" class="background-image" />

        <!-- B: 主体图，可移动、缩放 -->
        <img ref="mainImage" :src="viewData.digital.src" class="moveable-image" />

        <!-- C: 道具图，可移动、缩放、旋转 -->
        <img v-if="viewData.material.src" ref="propImage" :src="viewData.material.src" class="moveable-image" />
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.canvasContainerWarp {
  height: calc(100% - 100px);
}
.canvasContainer {
  box-sizing: border-box;
  padding: 0;
  left: 50%;
  top: 50%;
  border: none;
}
.background-image {
  position: absolute;
  width: 100%;
  height: 100%;
  // object-fit: cover;
  user-select: none;
  // 禁止拖拽
  pointer-events: none;
  z-index: 0; /* 背景图层级最低 */
}

.moveable-image {
  position: absolute;
  z-index: 1; /* 设置较高层级，以确保在背景图之上 */
}
</style>
